home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cfengine-1.5.3 / src / popen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-21  |  8.7 KB  |  472 lines

  1.  
  2. /* cfengine for GNU
  3.  
  4.         Copyright (C) 1995
  5.         Free Software Foundation, Inc.
  6.  
  7.    This file is part of GNU cfengine - written and maintained 
  8.    by Mark Burgess, Dept of Computing and Engineering, Oslo College,
  9.    Dept. of Theoretical physics, University of Oslo
  10.  
  11.    This program is free software; you can redistribute it and/or modify it
  12.    under the terms of the GNU General Public License as published by the
  13.    Free Software Foundation; either version 2, or (at your option) any
  14.    later version.
  15.  
  16.    This program is distributed in the hope that it will be useful,
  17.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.    GNU General Public License for more details.
  20.  
  21.   You should have received a copy of the GNU General Public License
  22.   along with this program; if not, write to the Free Software
  23.   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  
  25. */
  26.  
  27. /*****************************************************************************/
  28. /*                                                                           */
  29. /* File: popen.c                                                             */
  30. /*                                                                           */
  31. /* Created: Tue Dec  2 02:14:16 1997                                         */
  32. /*                                                                           */
  33. /* popen replacement for POSIX 2 avoiding shell piggyback                    */
  34. /*                                                                           */
  35. /*****************************************************************************/
  36.  
  37. #include "cf.defs.h"
  38. #include "cf.extern.h" 
  39.  
  40. pid_t *CHILD;
  41. int    MAXFD = 20; /* Max number of simultaneous pipes */
  42.  
  43. /*****************************************************************************/
  44.  
  45. FILE *cfpopen(command,type)
  46.     
  47. char *command, *type;
  48.  
  49.  { char arg[maxshellargs][bufsize];
  50.    int i, argc, pd[2];
  51.    char **argv;
  52.    pid_t pid;
  53.    FILE *pp = NULL;
  54.  
  55.  Debug("cfpopen(%s)\n",command);
  56.  
  57.  if ((*type != 'r' && *type != 'w') || (type[1] != '\0'))
  58.     {
  59.     errno = EINVAL;
  60.     return NULL;
  61.     }
  62.  
  63.  if (CHILD == NULL)   /* first time */
  64.     {
  65.     if ((CHILD = calloc(MAXFD,sizeof(pid_t))) == NULL)
  66.        {
  67.        return NULL;
  68.        }
  69.     }
  70.  
  71.  if (pipe(pd) < 0)        /* Create a pair of descriptors to this process */
  72.     {
  73.     return NULL;
  74.     }
  75.  
  76.  if ((pid = fork()) == -1)
  77.     {
  78.     return NULL;
  79.     }
  80.  
  81.  if (pid == 0)
  82.     {
  83.     switch (*type)
  84.        {
  85.        case 'r':
  86.  
  87.        close(pd[0]);        /* Don't need output from parent */
  88.  
  89.        if (pd[1] != 1)
  90.           {
  91.           dup2(pd[1],1);    /* Attach pp=pd[1] to our stdout */
  92.           dup2(pd[1],2);    /* Merge stdout/stderr */
  93.           close(pd[1]);
  94.           }
  95.  
  96.        break;
  97.  
  98.        case 'w':
  99.  
  100.        close(pd[1]);
  101.  
  102.        if (pd[0] != 0)
  103.           {
  104.           dup2(pd[0],0);
  105.           close(pd[0]);
  106.           }
  107.        }
  108.  
  109.     for (i = 0; i < MAXFD; i++)
  110.        {
  111.        if (CHILD[i] > 0)
  112.       {
  113.       close(CHILD[i]);
  114.       }
  115.  
  116.        argc = SplitCommand(command,arg);
  117.        argv = (char **) malloc((argc+1)*sizeof(char *));
  118.  
  119.        if (argv == NULL)
  120.       {
  121.       FatalError("Out of memory");
  122.       }
  123.        
  124.        for (i = 0; i < argc; i++)
  125.       {
  126.       argv[i] = arg[i];
  127.       }
  128.  
  129.        argv[i] = (char *) NULL;
  130.  
  131.        if (execv(arg[0],argv) == -1)
  132.       {
  133.       sprintf(OUTPUT,"Couldn't run %s",arg[0]);
  134.       CfLog(cferror,OUTPUT,"execv");
  135.       }
  136.  
  137.        _exit(1);
  138.        }
  139.     }
  140.  else
  141.     {
  142.     switch (*type)
  143.        {
  144.        case 'r':
  145.  
  146.        close(pd[1]);
  147.        
  148.        if ((pp = fdopen(pd[0],type)) == NULL)
  149.           {
  150.           return NULL;
  151.           }
  152.        break;
  153.        
  154.        case 'w':
  155.  
  156.        close(pd[0]);
  157.        
  158.        if ((pp = fdopen(pd[1],type)) == NULL)
  159.           {
  160.           return NULL;
  161.           }
  162.        }
  163.  
  164.     CHILD[fileno(pp)] = pid;
  165.     return pp;
  166.     }
  167.  }
  168.  
  169. /*****************************************************************************/
  170.  
  171. FILE *cfpopen_sh(command,type)
  172.     
  173. char *command, *type;
  174.  
  175.  { char arg[maxshellargs][bufsize];
  176.    int i, argc, pd[2];
  177.    char **argv;
  178.    pid_t pid;
  179.    FILE *pp = NULL;
  180.  
  181.  Debug("cfpopen(%s)\n",command);
  182.  
  183.  if ((*type != 'r' && *type != 'w') || (type[1] != '\0'))
  184.     {
  185.     errno = EINVAL;
  186.     return NULL;
  187.     }
  188.  
  189.  if (CHILD == NULL)   /* first time */
  190.     {
  191.     if ((CHILD = calloc(MAXFD,sizeof(pid_t))) == NULL)
  192.        {
  193.        return NULL;
  194.        }
  195.     }
  196.  
  197.  if (pipe(pd) < 0)        /* Create a pair of descriptors to this process */
  198.     {
  199.     return NULL;
  200.     }
  201.  
  202.  if ((pid = fork()) == -1)
  203.     {
  204.     return NULL;
  205.     }
  206.  
  207.  if (pid == 0)
  208.     {
  209.     switch (*type)
  210.        {
  211.        case 'r':
  212.  
  213.        close(pd[0]);        /* Don't need output from parent */
  214.  
  215.        if (pd[1] != 1)
  216.           {
  217.           dup2(pd[1],1);    /* Attach pp=pd[1] to our stdout */
  218.           dup2(pd[1],2);    /* Merge stdout/stderr */
  219.           close(pd[1]);
  220.           }
  221.  
  222.        break;
  223.  
  224.        case 'w':
  225.  
  226.        close(pd[1]);
  227.  
  228.        if (pd[0] != 0)
  229.           {
  230.           dup2(pd[0],0);
  231.           close(pd[0]);
  232.           }
  233.        }
  234.  
  235.     for (i = 0; i < MAXFD; i++)
  236.        {
  237.        if (CHILD[i] > 0)
  238.       {
  239.       close(CHILD[i]);
  240.       }
  241.        }
  242.  
  243.     execl("/bin/sh","sh","-c",command,NULL);
  244.     _exit(127);
  245.     }
  246.  else
  247.     {
  248.     switch (*type)
  249.        {
  250.        case 'r':
  251.        
  252.        close(pd[1]);
  253.        
  254.        if ((pp = fdopen(pd[0],type)) == NULL)
  255.           {
  256.           return NULL;
  257.           }
  258.        break;
  259.        
  260.        case 'w':
  261.        
  262.        close(pd[0]);
  263.        
  264.        if ((pp = fdopen(pd[1],type)) == NULL)
  265.           {
  266.           return NULL;
  267.           }
  268.        }
  269.  
  270.     CHILD[fileno(pp)] = pid;
  271.     return pp;
  272.     }
  273.  }
  274.  
  275.  
  276. /******************************************************************************/
  277.  
  278. cfpclose(pp)
  279.  
  280. FILE *pp;
  281.  
  282. { int fd, status;
  283.   pid_t pid;
  284.  
  285. Debug("cfpclose(pp)\n");
  286.  
  287. if (CHILD == NULL)  /* popen hasn't been called */
  288.    {
  289.    return -1;
  290.    }
  291.  
  292. fd = fileno(pp);
  293.  
  294. if ((pid = CHILD[fd]) == 0)
  295.    {
  296.    return -1;
  297.    }
  298.  
  299. CHILD[fd] = 0;
  300.  
  301. if (fclose(pp) == EOF)
  302.    {
  303.    return -1;
  304.    }
  305.  
  306. Debug("cfpopen - Waiting for process %d\n",pid); 
  307.  
  308. #ifdef HAVE_WAITPID
  309.  
  310. while(waitpid(pid,&status,0) < 0)
  311.    {
  312.    if (errno != EINTR)
  313.       {
  314.       return -1;
  315.       }
  316.    }
  317.  
  318.  return status; 
  319.  
  320. #else
  321.       
  322.  if (wait(&status) != pid)
  323.     {
  324.     return -1;
  325.     }
  326.  else
  327.     {
  328.     if (WIFSIGNALED(status))
  329.        {
  330.        return -1;
  331.        }
  332.     
  333.     if (! WIFEXITED(status))
  334.        {
  335.        return -1;
  336.        }
  337.  
  338.     return (WEXITSTATUS(status));
  339.     }
  340. #endif
  341. }
  342.  
  343. /******************************************************************************/
  344.  
  345. cfpclose_def(pp,defines)
  346.  
  347. FILE *pp;
  348. char *defines;
  349.  
  350. { int fd, status;
  351.   pid_t pid;
  352.  
  353. Debug("cfpclose(pp)\n");
  354.  
  355. if (CHILD == NULL)  /* popen hasn't been called */
  356.    {
  357.    return -1;
  358.    }
  359.  
  360. fd = fileno(pp);
  361.  
  362. if ((pid = CHILD[fd]) == 0)
  363.    {
  364.    return -1;
  365.    }
  366.  
  367. CHILD[fd] = 0;
  368.  
  369. if (fclose(pp) == EOF)
  370.    {
  371.    return -1;
  372.    }
  373.  
  374. Debug("cfpopen - Waiting for process %d\n",pid); 
  375.  
  376. #ifdef HAVE_WAITPID
  377.  
  378. while(waitpid(pid,&status,0) < 0)
  379.    {
  380.    if (errno != EINTR)
  381.       {
  382.       return -1;
  383.       }
  384.    }
  385.  
  386. if (status == 0)
  387.    {
  388.    AddMultipleClasses(defines);
  389.    }
  390.  
  391. return status; 
  392.  
  393. #else
  394.       
  395.  if (wait(&status) != pid)
  396.     {
  397.     return -1;
  398.     }
  399.  else
  400.     {
  401.     if (WIFSIGNALED(status))
  402.        {
  403.        return -1;
  404.        }
  405.     
  406.     if (! WIFEXITED(status))
  407.        {
  408.        return -1;
  409.        }
  410.  
  411.     if (WEXITSTATUS(status) == 0)
  412.        {
  413.        AddMultipleClasses(defines);
  414.        }
  415.     
  416.     return (WEXITSTATUS(status));
  417.     }
  418. #endif
  419. }
  420.  
  421.  
  422. /*******************************************************************/
  423. /* Command exec aids                                               */
  424. /*******************************************************************/
  425.  
  426. SplitCommand(comm,arg)
  427.  
  428. char *comm, arg[maxshellargs][bufsize];
  429.  
  430. { char *sp;
  431.   int i = 0, j;
  432.   char buff[bufsize];
  433.  
  434. for (sp = comm; sp < comm+strlen(comm); sp++)
  435.    {
  436.    bzero(buff,bufsize);
  437.  
  438.    if (i >= maxshellargs-1)
  439.       {
  440.       CfLog(cferror,"Too many arguments in embedded script","");
  441.       FatalError("Use a wrapper");
  442.       }
  443.  
  444.    while (*sp == ' ' || *sp == '\t')
  445.       {
  446.       sp++;
  447.       }
  448.  
  449.    switch (*sp)
  450.       {
  451.       case '\0': return(i-1);
  452.  
  453.       case '\"': sscanf (++sp,"%[^\"]",arg[i]);
  454.                  break;
  455.       case '\'': sscanf (++sp,"%[^\']",arg[i]);
  456.                  break;
  457.       case '`':  sscanf (++sp,"%[^`]",arg[i]);
  458.              break;
  459.       default:   sscanf (sp,"%s",arg[i]);
  460.                  break;
  461.       }
  462.  
  463.    sp += strlen(arg[i]);
  464.    i++;
  465.    }
  466.  
  467. return (i);
  468. }
  469.  
  470.  
  471.  
  472.